package com.example.ecmftlutil;


import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@SuppressWarnings("unused")
public class LayersUtils {
    /**
     * @param parentCode           父级code
     * @param codeAndParentCodeMap code和父级code映射信息
     * @param layers               开始层数
     * @return 层数（根据开始层数进行递增++）
     */
    private static <R> int recursionCalculation(R parentCode, Map<String, R> codeAndParentCodeMap, int layers) {
        if (null == parentCode) {
            return layers;
        }
        if (parentCode instanceof String) {
            return recursionCalculation(codeAndParentCodeMap.get((String) parentCode), codeAndParentCodeMap, layers + 1);
        }
        if (parentCode instanceof List<?>) {
            List<Integer> layersList = new ArrayList<>();
            layersList.add(0);
            for (Object objParentCode : (List<?>) parentCode) {
                layers = recursionCalculation(codeAndParentCodeMap.get((String) objParentCode), codeAndParentCodeMap, layers + 1);
                layersList.add(layers);
            }
            return layersList.stream().max(Comparator.comparing(Integer::intValue)).get();
        }
        return 0;
    }

    /**
     * @param list       被排序的集合
     * @param code       当前code获取函数
     * @param parentCode 上级code获取函数
     * @return 根据层数无顺序排序的list
     */
    public static <T extends Layers, R> List<T> calculationLayers(List<T> list, Function<T, String> code, Function<T, R> parentCode) {
        Map<String, R> codeAndParentCodeMap = new HashMap<>();
        for (T t : list) {
            try {
                String typeCode = code.apply(t);
                R typeParentCode = null;
                try {
                    typeParentCode = parentCode.apply(t);
                } catch (Exception ignored) {
                }
                codeAndParentCodeMap.put(typeCode, typeParentCode);
            } catch (Exception ignored) {
            }
        }
        list.forEach(item -> item.setLayers(recursionCalculation(parentCode.apply(item), codeAndParentCodeMap, 0)));
        return list.stream().sorted(Comparator.comparing(T::getLayers)).collect(Collectors.toList());
    }

    public interface Layers {
        int getLayers();

        void setLayers(int layers);
    }

}

